/*
 * SubSonic - http://subsonicproject.com
 * 
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an 
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;

namespace SubSonic.QueryEngine
{
    /// <summary>
    /// Summary for the SqlQuery class
    /// </summary>
    public class SqlQuery
    {
        private string _columnList = String.Empty;
        private QueryCommand _command;
        private SqlParser _parser = null;

        /// <summary>
        /// 
        /// </summary>
        public List<Constraint> Constraints = new List<Constraint>();

        /// <summary>
        /// 
        /// </summary>
        public NameValueCollection InsertSettings;

        /// <summary>
        /// 
        /// </summary>
        protected bool IsDistinct = false;

        internal List<Join> Joins = new List<Join>();

        /// <summary>
        /// 
        /// </summary>
        protected QueryType QueryType = QueryType.Select;

        /// <summary>
        /// 
        /// </summary>
        public TableSchema.TableCollection Tables = new TableSchema.TableCollection();

        /// <summary>
        /// 
        /// </summary>
        protected string TopQualifier = String.Empty;

        /// <summary>
        /// 
        /// </summary>
        public NameValueCollection UpdateSettings;


        #region Execution

        /// <summary>
        /// Executes the reader.
        /// </summary>
        /// <returns></returns>
        public IDataReader ExecuteReader()
        {
            return null;
        }

        /// <summary>
        /// Gets the SQL.
        /// </summary>
        /// <returns></returns>
        public string GetSql()
        {
            return String.Empty;
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            return GetSql();
        }

        #endregion


        #region Where

        /// <summary>
        /// Wheres the specified column name.
        /// </summary>
        /// <param name="columnName">Name of the column.</param>
        /// <returns></returns>
        public Constraint Where(string columnName)
        {
            return InitConstraint(columnName);
        }

        /// <summary>
        /// Ands the specified column name.
        /// </summary>
        /// <param name="columnName">Name of the column.</param>
        /// <returns></returns>
        public Constraint And(string columnName)
        {
            return InitConstraint(columnName);
        }

        /// <summary>
        /// Ors the specified column name.
        /// </summary>
        /// <param name="columnName">Name of the column.</param>
        /// <returns></returns>
        public Constraint Or(string columnName)
        {
            Constraint c = InitConstraint(columnName);
            c.Condition = ConstraintType.Or;
            return c;
        }

        /// <summary>
        /// Inits the constraint.
        /// </summary>
        /// <param name="columnName">Name of the column.</param>
        /// <returns></returns>
        private Constraint InitConstraint(string columnName)
        {
            Constraint c = new Constraint();
            c.query = this;
            c.ColumnName = columnName;
            return c;
        }

        #endregion


        #region Joins

        /// <summary>
        /// Joins the specified foreign table.
        /// </summary>
        /// <param name="foreignTable">The foreign table.</param>
        /// <returns></returns>
        public SqlQuery Join(TableSchema foreignTable)
        {
            return this;
        }

        /// <summary>
        /// Joins the specified foreign table.
        /// </summary>
        /// <param name="foreignTable">The foreign table.</param>
        /// <param name="joinType">Type of the join.</param>
        /// <returns></returns>
        public SqlQuery Join(TableSchema foreignTable, JoinType joinType)
        {
            return this;
        }

        /// <summary>
        /// Joins the specified foreign table.
        /// </summary>
        /// <param name="foreignTable">The foreign table.</param>
        /// <param name="fromField">From field.</param>
        /// <param name="toField">To field.</param>
        /// <returns></returns>
        public SqlQuery Join(string foreignTable, string fromField, string toField)
        {
            return this;
        }

        /// <summary>
        /// Joins the specified foreign table.
        /// </summary>
        /// <param name="foreignTable">The foreign table.</param>
        /// <param name="joinType">Type of the join.</param>
        /// <returns></returns>
        public SqlQuery Join(string foreignTable, JoinType joinType)
        {
            return this;
        }

        /// <summary>
        /// Joins the specified foreign table.
        /// </summary>
        /// <param name="foreignTable">The foreign table.</param>
        /// <param name="fromField">From field.</param>
        /// <param name="toField">To field.</param>
        /// <param name="joinType">Type of the join.</param>
        /// <returns></returns>
        public SqlQuery Join(string foreignTable, string fromField, string toField, JoinType joinType)
        {
            return this;
        }

        #endregion


        /// <summary>
        /// Gets or sets the command.
        /// </summary>
        /// <value>The command.</value>
        public QueryCommand Command
        {
            get { return _command; }
            set { _command = value; }
        }

        /// <summary>
        /// Gets or sets the column list.
        /// </summary>
        /// <value>The column list.</value>
        public string ColumnList
        {
            get { return _columnList; }
            set { _columnList = value; }
        }

        /// <summary>
        /// Gets the SQL parser.
        /// </summary>
        /// <param name="providerName">Name of the provider.</param>
        /// <returns></returns>
        protected SqlParser GetSqlParser(string providerName)
        {
            if(_parser == null)
            {
                DataProvider p = DataService.Providers[providerName];
                if(p is SqlDataProvider || p is ELib2DataProvider || p is ELib3DataProvider)
                    _parser = new SqlServerParser();
                else if(p is MySqlDataProvider || p is MySqlInnoDBDataProvider) {}
                else if(p is SQLiteDataProvider) {}
                else if(p is SqlCEProvider) {}
                else if(p is OracleDataProvider) {}
                else
                    throw new Exception("Can't parse the query - don't have a parser for this DB");
            }
            return _parser;
        }

        /// <summary>
        /// Builds the command.
        /// </summary>
        /// <returns></returns>
        private QueryCommand BuildCommand()
        {
            QueryCommand result = null;
            //have the data service build the SQL for us, since SQL is provider-dependent
            //will also build the command

            return result;
        }
    }
}
